package com.example.demo.config;

import com.example.demo.entity.User;
import com.example.demo.utils.UserContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;


/**
 * 请求处理拦截器
 * 用于处理跨域请求和响应头设置
 */
@Component
public class ProcessInterceptor implements HandlerInterceptor {

    /**
     * 在请求处理之前进行调用
     *
     * @param httpServletRequest  请求对象
     * @param httpServletResponse 响应对象
     * @param o                   处理器
     * @return true表示继续流程（如调用下一个拦截器或处理器），
     * false表示流程中断（如登录检查失败），不会继续调用其它拦截器或处理器
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
        // 设置允许跨域访问的域名，*表示接受任意域名的请求
        httpServletResponse.setHeader("Access-Control-Allow-Origin", "*");
        // 设置允许的请求头字段
        httpServletResponse.setHeader("Access-Control-Allow-Headers", "*");
        // 设置允许的请求方法
        httpServletResponse.setHeader("Access-Control-Allow-Methods", "PUT,POST,GET,DELETE,OPTIONS");


        String method = httpServletRequest.getMethod();
        // 如果是OPTIONS请求（预检请求），直接返回成功状态码200
        if (method.equals("OPTIONS")) {
            httpServletResponse.setStatus(200);
            return false;
        }

        //TODO 这里写死了，但是可以做一个管理员可以操作的角色权限表，来分配每个角色能够访问到什么内容，然后拦截器拦截所有，然后判断路径是否在用户权限内
        User user = (User) httpServletRequest.getSession().getAttribute("user");
        System.out.println("拦截器用户信息：" + user);
        // 对于前往/teacher的请求做鉴权，从session中获取用户信息，获取到User.roleId==1管理员权限后放行
        if (httpServletRequest.getRequestURI().startsWith("/teacher")) {

            if (user != null && (user.getRoleId() == 1 || user.getRoleId() == 2)) {
                UserContext.setUser(user); // 将用户信息存储到线程本地变量中
                return true;
            } else {
                //我们规定401为未登陆402为登陆权限不足
                httpServletResponse.setStatus(402);
                return false;
            }
        }

        // 教师和管理员可以修改题库，题库表做二次鉴权，老师只能访问自己的题库
        if (httpServletRequest.getRequestURI().startsWith("/question-bank")) {
            if (user != null && (user.getRoleId() == 1 || user.getRoleId() == 2)) {
                UserContext.setUser(user); // 将用户信息存储到线程本地变量中
                return true;
            } else {
                //我们规定401为未登陆402为登陆权限不足
                httpServletResponse.setStatus(402);
                return false;
            }
        }

        // 如果有用户信息，将其存储到线程本地变量中
        if (user != null) {
            UserContext.setUser(user);
        }

        return true;
    }

    /**
     * 在请求处理之后，视图渲染之前进行调用
     *
     * @param httpServletRequest  请求对象
     * @param httpServletResponse 响应对象
     * @param o                   处理器
     * @param modelAndView        ModelAndView对象
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
        // 请求处理之后进行调用，但是在视图被渲染之前
    }

    /**
     * 在整个请求结束之后被调用，也就是在DispatcherServlet渲染了对应的视图之后执行（主要是用于进行资源清理工作）
     *
     * @param httpServletRequest  请求对象
     * @param httpServletResponse 响应对象
     * @param o                   处理器
     * @param e                   异常对象
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
        // 在整个请求结束之后被调用，也就是在DispatcherServlet渲染了对应的视图之后执行（主要是用于进行资源清理工作）
        // 清除线程本地变量中的用户信息，防止内存泄漏
        UserContext.removeUser();
    }
}